package pl.edu.pw.mini.java2.Communicator.Server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.*;

/**
 * Server worker class
 * 
 * Used to communicate with connected client over socket
 * 
 */
public class ClientHandler {

	private Socket client = null;
	private ReaderWorker reader;
	private WriterWorker writer;
	private String login;
	private boolean isBusy;
	private ClientHandler pair = null;

	public WriterWorker getWriter() {
		return writer;
	}

	public ReaderWorker getReader() {
		return reader;
	}

	public String getName() {
		if (login == null)
			return "CLIENT_NOT_LOGGED";
		return login;
	}

	public boolean getIsBusy() {
		return isBusy;
	}

	public void setIsBusy(boolean isBusy) {
		this.isBusy = isBusy;
	}

	public void setPair(ClientHandler pair) {
		this.pair = pair;
		if (pair != null)
			ServerLogger.print(getName() + " sets pair with " + pair.getName());
		else
			ServerLogger.print(getName() + " clears pair");
	}

	public ClientHandler getPair() {
		return pair;
	}

	public ClientHandler(Socket client) {
		this.client = client;
		setIsBusy(false);
		try {
			client.setKeepAlive(true);
		} catch (SocketException e) {
			ServerLogger.print(e.toString());
		}
	}

	public void start() {
		if (client == null)
			return;
		try {
			DataInputStream in = new DataInputStream(client.getInputStream());
			DataOutputStream out = new DataOutputStream(client
					.getOutputStream());

			reader = new ReaderWorker(this, in);
			writer = new WriterWorker(this, out);
			reader.start();
			writer.start();
		} catch (Exception e) {
			ServerLogger.print(e.toString());
		}
	}

	public void Disconnect() {
		ServerLogger.print(getName() + " is disconnecting.");
		if (pair != null) {
			synchronized (ClientsManager.Instance()) {
				try {
					pair.getWriter().sendMessage(
							new Message(Message.CHAT_REJECT));
					pair.setPair(null);
					pair.setIsBusy(false);
					setPair(null);
					setIsBusy(true);
				} catch (Exception ignored) {
				}
			}
		}
		reader.close();
		writer.close();
		ClientsManager.Instance().Logout(login);
		try {
			client.close();
		} catch (IOException ignore) {
		}
	}

	public void Login(String login) throws Exception {
		if (this.login != null)
			throw new IllegalStateException();
		this.login = login;
		try {
			ClientsManager.Instance().Logon(login, this);
		} catch (Exception exception) {
			this.login = null;
			throw exception;
		}
	}
}
